use std::ffi::CString;
use std::os::raw::c_void;
use std::ptr;
use std::thread;
use std::time::Duration;
use std::io::Write;

const SHM_SIZE: usize = 1024;
const SHM_NAME: &str = \"shm_example\";

#[repr(C)]
struct Message {
    written: i32,
    text: [u8; SHM_SIZE - std::mem::size_of::<i32>()],
}

/// Server function that listens for incoming messages
fn server(shm: *mut Message) {
    let epfd = unsafe { libc::epoll_create1(0) };
    if epfd < 0 {
        panic!(\"Failed to create epoll\");
    }

    let mut ev = libc::epoll_event {
        events: libc::EPOLLIN as u32,
        u64: 0,
    };
    ev.u64 = 0;

    if unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, 0, &mut ev as *mut libc::epoll_event) } == -1 {
        panic!(\"Failed to add epoll control\");
    }

    loop {
        let mut events = libc::epoll_event {
            events: 0,
            u64: 0,
        };
        let nfds = unsafe { libc::epoll_wait(epfd, &mut events, 1, 500) };
        if nfds == -1 {
            panic!(\"Failed to wait for epoll events\");
        }

        if unsafe { (*shm).written != 0 } {
            let text = unsafe { std::str::from_utf8_unchecked(&(*shm).text[..(*shm).written as usize]) };
            println!(\"Server received: {}\", text);
            unsafe { (*shm).written = 0 };
        }
    }
}

/// Client function that sends messages
fn client(shm: *mut Message) {
    let mut buf = [0u8; SHM_SIZE - std::mem::size_of::<i32>()];
    loop {
        while unsafe { (*shm).written == 1 } {
            thread::sleep(Duration::from_secs(1));
        }

        print!(\"Enter some text: \");
        let _ = std::io::stdout().flush();

        let mut input = String::new();
        std::io::stdin().read_line(&mut input).expect(\"Failed to read input\");

        let input = input.trim().as_bytes();
        buf[..input.len()].copy_from_slice(input);
        unsafe {
            (*shm).text[..input.len()].copy_from_slice(&buf[..input.len()]);
            (*shm).written = 1;
        }
    }
}

fn main() {
    unsafe {
        libc::unlink(CString::new(SHM_NAME).unwrap().as_ptr());
        let shm_fd = libc::open(CString::new(SHM_NAME).unwrap().as_ptr(), libc::O_CREAT | libc::O_RDWR, 0o666);
        if shm_fd == -1 {
            panic!(\"Failed to open shared memory\");
        }

        if libc::ftruncate(shm_fd, std::mem::size_of::<Message>() as i64) == -1 {
            panic!(\"Failed to set shared memory size\");
        }

        let shm = libc::mmap(ptr::null_mut(), std::mem::size_of::<Message>(),
                             libc::PROT_READ | libc::PROT_WRITE, libc::MAP_SHARED,
                             shm_fd, 0) as *mut Message;
        if shm == libc::MAP_FAILED as *mut Message {
            panic!(\"Failed to map shared memory\");
        }

        (*shm).written = 0;

        let pid = libc::fork();
        if pid < 0 {
            panic!(\"Failed to fork\");
        }

        if pid == 0 {
            // Child process - client
            client(shm);
        } else {
            // Parent process - server
            server(shm);
        }

        if libc::munmap(shm as *mut c_void, std::mem::size_of::<Message>()) == -1 {
            panic!(\"Failed to unmap shared memory\");
        }

        if libc::unlink(CString::new(SHM_NAME).unwrap().as_ptr()) == -1 {
            panic!(\"Failed to unlink shared memory\");
        }
    }
}